function toStrFn(item) {
	if (item == null) {
		return 'NULL'
	} else if (item == undefined) {
		return 'UNDEFINED'
	} else if (typeof item === 'string' || item instanceof String) {
		return `${item}`
	}
	return item.toString()
}
class ValuePair {
	constructor(key, value) {
		this.key = key
		this.value = value
	}
	toString() {
		return `[#${this.key}: ${this.value}]`
	}
}
export default class hashTable {
	#toStrFn = toStrFn
	#table = {}
    // 普通的散列函数
	loseloseHashCode(key) {
		if (typeof key === 'number') {
			return key
		}
		const tableKey = this.#toStrFn(key)
		let hash = 0
		// 根据key的每一个字符的ASCII码值的和得到一个数
		for (let i = 0; i < tableKey.length; i++) {
			hash += tableKey.charCodeAt(i)
		}
		// 为了得到比较小的值 可以和任意数取余数
		return hash % 37
	}
    // 更好的散列函数
	djbHashCode(key) {
		const tableKey = this.toStrFn(key)
		let hash = 5381
		for (let i = 0; i < tableKey.length; i++) {
			hash = hash * 33 + tableKey.charCodeAt(i)
		}
		return hash % 1013
	}
	hashCode(key) {
        // 选择其一
		// return this.loseloseHashCode(key)
		return this.djbHashCode(key)
	}
	put(key, value) {
		if (key != null && value != null) {
			const position = this.hashCode(key)
			this.#table[position] = new ValuePair(key, value)
			return true
		}
		return false
	}
	get(key) {
		const valuePair = this.#table[this.hashCode(key)]
		return valuePair == null ? undefined : valuePair.value
	}
	remove(key) {
		const hash = this.hashCode(key)
		const valuePair = this.#table[hash]
		if (valuePair != null) {
			delete this.#table[hash]
			return true
		}
		return false
	}
	keyValues() {
		return Object.values(this.#table)
	}
	keys() {
		return this.keyValues().map(valuePair => valuePair.key)
	}
	values() {
		return this.keyValues().map(valuePair => valuePair.value)
	}
	clear() {
		this.#table = {}
	}
	size() {
		return Object.keys(this.#table).length
	}
	isEmpty() {
		return this.size() === 0
	}
	forEach(callbackFn) {
		const valuePairs = this.keyValues()
		for (let i = 0; i < valuePairs.length; i++) {
			const result = callbackFn(valuePairs[i].key, valuePairs[i].value)
			if (result === false) {
				break
			}
		}
	}
	toString() {
		if (this.isEmpty()) {
			return ''
		}
		const valuePairs = this.keyValues()
		let objString = `${valuePairs[0].toString()}`
		for (let i = 1; i < valuePairs.length; i++) {
			objString = `${objString},${valuePairs[i].toString()}`
		}
		return objString
	}
}
